using System.Linq;
using FireStarter.Base;
using FireStarter.Base.BusinessObjectMerger;
using FireStarterModeller.BO;
using FireStarterModeller.Logic.MergeBusinessObjects;
using FireStarterModeller.Test.BO;
using Habanero.Testability;
using NUnit.Framework;

namespace FireStarterModeller.Test.Logic.MergeBusinessObjects
{
    [TestFixture]
    public class TestMergeUIView
    {
        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            TestUtilsLogic.SetupFixture();
        }
        [SetUp]
        public virtual void SetupTest()
        {
            TestUtilsLogic.SetupTest();
        }


        private static void SetOrdinalPos(UIGridColumnInfo uiGridColumnInfo)
        {
            uiGridColumnInfo.OrdinalPosition = GetValidOrdinalPos(uiGridColumnInfo);
        }

        private static int? GetValidOrdinalPos(UIGridColumnInfo uiGridColumnInfo)
        {
            return GetFactory().GetValidPropValue(uiGridColumnInfo, gridColumn => gridColumn.OrdinalPosition);
        }

        private static BOTestFactory<UIGridColumnInfo> GetFactory()
        {
            return TestUtilsUIGridColumnInfo.GetFactory();
        }

        [Test]
        public void Test_MergeUIView_WhenMerge_ShouldUpdateUIView()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIView> mergeBO = MergeableBORegistry.Instance.Resolve<UIView>();
            var uiTestFactory = TestUtilsUIView.GetFactory();
            var fromUIView = uiTestFactory
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var toUIView = new UIView
                               {
                                   ViewName = uiTestFactory.GetValidPropValue(view => view.ViewName)
                               };
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(fromUIView.ViewName, toUIView.ViewName);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIView, toUIView);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromUIView.ViewName, toUIView.ViewName);
        }

        [Test]
        public void Test_MergeUIView_WhenAddGrid_ShouldCloneGridAndSetToView()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIView> mergeBO = MergeableBORegistry.Instance.Resolve<UIView>();
            var uiTestFactory = TestUtilsUIView.GetFactory();
            var fromUIView = uiTestFactory
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var fromGrid = new UIGridInfo
            {
                SortColumn = RandomValueGen.GetRandomString()
            };
            fromUIView.UIGridInfo = fromGrid;
            var toView = new UIView();
            //---------------Assert Precondition----------------
            Assert.IsNull(toView.UIGridInfo);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIView, toView);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toView.UIGridInfo);
            Assert.AreEqual(fromGrid.SortColumn, toView.UIGridInfo.SortColumn);
            Assert.AreNotSame(fromGrid, toView.UIGridInfo);
        }
        [Test]
        public void Test_MergeUIView_WhenUpdatedGrid_ShouldUpdateGrid()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIView> mergeBO = MergeableBORegistry.Instance.Resolve<UIView>();
            var uiTestFactory = TestUtilsUIView.GetFactory();
            var fromUIView = uiTestFactory
              .WithOutSingleRelationships()
              .CreateValidBusinessObject();

            var fromGridInfo = new UIGridInfo
            {
                SortColumn = RandomValueGen.GetRandomString()
            };
            fromUIView.UIGridInfo = fromGridInfo;
            var expectedToGridFilter = new UIGridInfo();
            expectedToGridFilter.SortColumn = RandomValueGen.GetRandomString();
            var toUIView = new UIView { UIGridInfo = expectedToGridFilter };

            //---------------Assert Precondition----------------
            Assert.IsNotNull(toUIView.UIGridInfo);
            Assert.AreNotEqual(fromGridInfo.SortColumn, toUIView.UIGridInfo.SortColumn);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIView, toUIView);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toUIView.UIGridInfo);
            Assert.AreEqual(fromGridInfo.SortColumn, toUIView.UIGridInfo.SortColumn);
            Assert.AreSame(expectedToGridFilter, toUIView.UIGridInfo);
            Assert.AreNotSame(fromGridInfo, toUIView.UIGridInfo);
        }


        [Test]
        public void Test_MergeUIView_WhenDeleteGrid_ShouldMarkPendingChangesDelete()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIView> mergeBO = MergeableBORegistry.Instance.Resolve<UIView>(); 
            var uiTestFactory = TestUtilsUIView.GetFactory();
            var fromUIView = uiTestFactory
              .WithOutSingleRelationships()
              .CreateValidBusinessObject();
            var toView = new UIView();
            var toGrid = new UIGridInfo
            {
                SortColumn = RandomValueGen.GetRandomString()
            };
            toView.UIGridInfo = toGrid;
            //---------------Assert Precondition----------------
            Assert.IsNotNull(toView.UIGridInfo);
            Assert.IsNull(fromUIView.UIGridInfo);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIView, toView);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toView.UIGridInfo);
            Assert.AreEqual(ChangeType.Delete, ((IMergableBo)toView.UIGridInfo).PendingChangeType);
        }



        [Test]
        public void Test_MergeUIView_WhenAddForm_ShouldCloneFormAndSetToView()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIView> mergeBO = MergeableBORegistry.Instance.Resolve<UIView>();
            var uiTestFactory = TestUtilsUIView.GetFactory();
            var fromUIView = uiTestFactory
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var fromGrid = new UIFormInfo
            {
                Title = RandomValueGen.GetRandomString()
            };
            fromUIView.UIFormInfo = fromGrid;
            var toView = new UIView();
            //---------------Assert Precondition----------------
            Assert.IsNull(toView.UIFormInfo);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIView, toView);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toView.UIFormInfo);
            Assert.AreEqual(fromGrid.Title, toView.UIFormInfo.Title);
            Assert.AreNotSame(fromGrid, toView.UIFormInfo);
        }
        [Test]
        public void Test_MergeUIView_WhenUpdatedForm_ShouldUpdateForm()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIView> mergeBO = MergeableBORegistry.Instance.Resolve<UIView>();
            var uiTestFactory = TestUtilsUIView.GetFactory();
            var fromUIView = uiTestFactory
              .WithOutSingleRelationships()
              .CreateValidBusinessObject();

            var fromGridInfo = new UIFormInfo
            {
                Title = RandomValueGen.GetRandomString()
            };
            fromUIView.UIFormInfo = fromGridInfo;
            var expectedToGridFilter = new UIFormInfo();
            expectedToGridFilter.Title = RandomValueGen.GetRandomString();
            var toUIView = new UIView { UIFormInfo = expectedToGridFilter };

            //---------------Assert Precondition----------------
            Assert.IsNotNull(toUIView.UIFormInfo);
            Assert.AreNotEqual(fromGridInfo.Title, toUIView.UIFormInfo.Title);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIView, toUIView);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toUIView.UIFormInfo);
            Assert.AreEqual(fromGridInfo.Title, toUIView.UIFormInfo.Title);
            Assert.AreSame(expectedToGridFilter, toUIView.UIFormInfo);
            Assert.AreNotSame(fromGridInfo, toUIView.UIFormInfo);
        }

        [Test]
        public void Test_MergeUIView_WhenDeleteForm_ShouldMarkPendingChangesDelete()
        {
            //---------------Set up test pack-------------------
            IMergeBO<UIView> mergeBO = MergeableBORegistry.Instance.Resolve<UIView>();
            var uiTestFactory = TestUtilsUIView.GetFactory();
            var fromUIView = uiTestFactory
              .WithOutSingleRelationships()
              .CreateValidBusinessObject();
            var toView = new UIView();
            var toGridFilter = new UIFormInfo
            {
                Title = RandomValueGen.GetRandomString()
            };
            toView.UIFormInfo = toGridFilter;
            //---------------Assert Precondition----------------
            Assert.IsNotNull(toView.UIFormInfo);
            Assert.IsNull(fromUIView.UIFormInfo);
            //---------------Execute Test ----------------------
            mergeBO.MergeBOFrom(fromUIView, toView);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toView.UIFormInfo);
            Assert.AreEqual(ChangeType.Delete, ((IMergableBo)toView.UIFormInfo).PendingChangeType);
        }

        #region Merge UIView From DMClass


        [Test]
        public void Test_MergeDMClass_ShouldMergeUIViews()
        {
            //---------------Set up test pack-------------------
            var uiColumnLayoutMerger = MergeableBORegistry.Instance.Resolve<DMClass>();
            var fromDMClass = TestUtilsDMClass.GetFactory()
                .WithMany(dmClass => dmClass.UIViews)
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var uiViews = fromDMClass.UIViews;
            SetViewName(uiViews[0]);
            SetViewName(uiViews[1]);
            SetViewName(uiViews[2]);
            var toDMClass = new DMClass();
            //---------------Assert Precondition----------------
            Assert.Greater(fromDMClass.UIViews.Count, 2);
            Assert.AreEqual(0, toDMClass.UIViews.Count);
            //---------------Execute Test ----------------------
            uiColumnLayoutMerger.MergeBOFrom(fromDMClass, toDMClass);
            //---------------Test Result -----------------------
            Assert.AreEqual(fromDMClass.UIViews.Count, toDMClass.UIViews.Count);
        }

        private static void SetViewName(UIView uiView)
        {
            uiView.ViewName = TestUtilsShared.GetRandomString();
        }

        [Test]
        public void Test_MergeDMClass_WhenTwoUpdatedViews_ShouldUpdateViews()
        {
            //---------------Set up test pack-------------------
            var uiColumnLayoutMerger = MergeableBORegistry.Instance.Resolve<DMClass>();
            var fromDMClass = TestUtilsDMClass.GetFactory()
                .WithTwo(dmClass => dmClass.UIViews)
                .WithOutSingleRelationships()
                .CreateValidBusinessObject();
            var uiViews = fromDMClass.UIViews;
            var fromUIView = uiViews[0];
            SetViewName(fromUIView);
            var fromUIView2 = uiViews[1];
            SetViewName(fromUIView2);

            var toDMClass = new DMClass();
            UIView expectedToUIView = AddCopiedUIView(toDMClass, fromUIView);
            UIView expectedToUIView2 = AddCopiedUIView(toDMClass, fromUIView2);

            //---------------Assert Precondition----------------
            Assert.AreEqual(2, fromDMClass.UIViews.Count);
            Assert.AreEqual(fromUIView.ViewName, expectedToUIView.ViewName);
            Assert.AreEqual(fromUIView2.ViewName, expectedToUIView2.ViewName);
            //---------------Execute Test ----------------------
            uiColumnLayoutMerger.MergeBOFrom(fromDMClass, toDMClass);
            //---------------Test Result -----------------------
            Assert.IsNotNull(toDMClass);
            Assert.AreEqual(2, toDMClass.UIViews.Count);
            var toUIView = toDMClass.UIViews.First();
            Assert.AreEqual(fromUIView.ViewName, toUIView.ViewName);
            var toUIView2 = toDMClass.UIViews.Last();
            Assert.AreEqual(fromUIView2.ViewName, toUIView2.ViewName);
            Assert.AreEqual(ChangeType.None, ((IMergableBo)expectedToUIView).PendingChangeType, "There are no other properties other than the ViewName to merge");
        }

        private static UIView AddCopiedUIView(DMClass toDMClass, UIView fromUIfield)
        {
            var expectedToUIView = new UIView { ViewName = fromUIfield.ViewName };
            //No other props other than viewname on UIView : expectedToUIView.LabelText = TestUtilsShared.GetRandomString();
            toDMClass.UIViews.Add(expectedToUIView);
            return expectedToUIView;
        }

        private static UIView CreateUIView(DMClass uiColumnLayout)
        {
            var uiView = uiColumnLayout.UIViews.CreateBusinessObject();
            uiView.ViewName = TestUtilsShared.GetRandomString();
            return uiView;
        }


        [Test]
        public void Test_MergeDMClass_WhenOneRemovedUiView_ShouldUpdateViewStatusToDelete()
        {
            //---------------Set up test pack-------------------
            var uiColumnLayoutMerger = MergeableBORegistry.Instance.Resolve<DMClass>();
            var fromDMClass = new DMClass();
            var fromUIView = CreateUIView(fromDMClass);
            var fromUIView2 = CreateUIView(fromDMClass);
            var toDMClass = new DMClass();
            UIView expectedToUIView = AddCopiedUIView(toDMClass, fromUIView);
            UIView expectedToUIView2 = AddCopiedUIView(toDMClass, fromUIView2);
            fromDMClass.UIViews.Remove(fromUIView2);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, fromDMClass.UIViews.Count);
            Assert.AreEqual(2, toDMClass.UIViews.Count);
            Assert.AreEqual(fromUIView.ViewName, expectedToUIView.ViewName);
            //No other props other than viewname on UIView :Assert.AreNotEqual(fromUIView.LabelText, expectedToUIView.LabelText);
            Assert.AreNotEqual(ChangeType.Update, ((IMergableBo)expectedToUIView).PendingChangeType);
            Assert.AreNotEqual(ChangeType.Delete, ((IMergableBo)expectedToUIView2).PendingChangeType);
            //---------------Execute Test ----------------------
            uiColumnLayoutMerger.MergeBOFrom(fromDMClass, toDMClass);
            //---------------Test Result -----------------------

            Assert.IsNotNull(toDMClass);
            Assert.AreEqual(2, toDMClass.UIViews.Count);
            var toUIView = toDMClass.UIViews.First();
            Assert.AreSame(toUIView, expectedToUIView);

            var toUIView2 = toDMClass.UIViews.Last();
            Assert.AreSame(toUIView2, expectedToUIView2);
            Assert.AreEqual(ChangeType.Delete, ((IMergableBo)toUIView2).PendingChangeType);
            Assert.AreEqual(ChangeType.None, ((IMergableBo) toUIView).PendingChangeType);
        }

        #endregion


    }
}